"""
数据库系统完整演示程序
展示从SQL解析到查询执行的完整流程
"""

import sys
import os
import time
import datetime
from typing import List, Dict, Any, Optional

# 添加路径
current_dir = os.path.dirname(os.path.abspath(__file__))
sys.path.insert(0, os.path.join(current_dir, 'SqlCompiler'))
sys.path.insert(0, os.path.join(current_dir, 'ExecutionEngine'))
sys.path.insert(0, current_dir)

# 导入SqlCompiler组件
from LexicalAnalysis import LexicalAnalyzer, Token
from SyntaxAnalysis import SyntaxAnalyzer  
from SemanticAnalysis import SemanticAnalyzer, Quadruple
from logical_plan_generator import LogicalPlanGenerator
from physical_plan_optimizer import PhysicalPlanOptimizer

# 导入ExecutionEngine组件
from ExecutionEngine.query_plan import QueryPlan, PlanBuilder
from ExecutionEngine.executor import QueryExecutor
from ExecutionEngine.types import ExecutionContext

# 导入存储引擎适配器
from ExecutionEngine.storage_adapter import StorageEngineAdapter

# 导入完整测试用例
from complete_test_cases import get_complete_test_cases


class OutputManager:
    """输出管理器 - 同时输出到控制台和文件"""
    
    def __init__(self, output_file: str = None):
        self.output_file = output_file
        self.file_handle = None
        
        if output_file:
            # 使用UTF-8编码打开文件，确保中文正确显示
            self.file_handle = open(output_file, 'w', encoding='utf-8')
    
    def print(self, *args, **kwargs):
        """同时打印到控制台和文件"""
        # 打印到控制台
        print(*args, **kwargs)
        
        # 打印到文件
        if self.file_handle:
            print(*args, **kwargs, file=self.file_handle)
            self.file_handle.flush()  # 立即写入文件
    
    def close(self):
        """关闭文件句柄"""
        if self.file_handle:
            self.file_handle.close()
            self.file_handle = None
    
    def __enter__(self):
        return self
    
    def __exit__(self, exc_type, exc_val, exc_tb):
        self.close()


# 全局输出管理器
output_mgr = None


def print_to_file(*args, **kwargs):
    """重写的print函数，同时输出到控制台和文件"""
    global output_mgr
    if output_mgr:
        output_mgr.print(*args, **kwargs)
    else:
        print(*args, **kwargs)


def print_header(title: str, level: int = 1):
    """打印标题"""
    if level == 1:
        print_to_file("\n" + "="*80)
        print_to_file(f"  {title}")
        print_to_file("="*80)
    elif level == 2:
        print_to_file(f"\n{'-'*60}")
        print_to_file(f"  {title}")
        print_to_file("-"*60)
    else:
        print_to_file(f"\n{'▶'*level} {title}")


def print_step(step_num: int, title: str):
    """打印步骤"""
    print_to_file(f"\n 步骤 {step_num}: {title}")
    print_to_file("─" * 50)


def print_tokens(tokens: List[Token], max_display: int = 15):
    """美观地打印Token列表"""
    valid_tokens = [t for t in tokens if t.type.name not in ['COMMENT', 'EOF']]
    
    print_to_file(f"识别出的Token (共{len(valid_tokens)}个):")
    print_to_file(f"{'序号':<4} {'类型':<12} {'值':<15} {'位置':<8}")
    print_to_file("-" * 45)
    
    for i, token in enumerate(valid_tokens[:max_display], 1):
        location = f"({token.line},{token.column})"
        print_to_file(f"{i:<4} {token.type.name:<12} {str(token.value):<15} {location:<8}")
    
    if len(valid_tokens) > max_display:
        print_to_file(f"... 还有 {len(valid_tokens) - max_display} 个Token")


def print_quadruples(quadruples: List[Quadruple]):
    """美观地打印四元式"""
    print_to_file(f"生成的四元式中间代码 (共{len(quadruples)}个):")
    print_to_file(f"{'序号':<4} {'操作符':<10} {'操作数1':<12} {'操作数2':<12} {'结果':<12}")
    print_to_file("-" * 55)
    
    for i, quad in enumerate(quadruples):
        print_to_file(f"{i:<4} {quad.op:<10} {quad.arg1:<12} {quad.arg2:<12} {quad.result:<12}")


def print_symbol_table(symbol_table: Dict):
    """美观地打印符号表"""
    print_to_file(f"符号表 (共{len(symbol_table)}个符号):")
    if symbol_table:
        print_to_file(f"{'符号名':<15} {'类型':<10} {'定义位置':<12}")
        print_to_file("-" * 40)
        for name, entry in symbol_table.items():
            location = f"({entry.line},{entry.column})" if hasattr(entry, 'line') and entry.line > 0 else "系统生成"
            entry_type = getattr(entry, 'type', 'unknown')
            print_to_file(f"{name:<15} {entry_type:<10} {location:<12}")
    else:
        print_to_file("  (符号表为空)")


def print_execution_results(results: List[Dict], max_display: int = 10):
    """美观地打印执行结果"""
    print_to_file(f"查询执行结果 (共{len(results)}条记录):")
    
    if not results:
        print_to_file("  (无结果)")
        return
    
    # 获取所有列名
    all_columns = set()
    for record in results:
        all_columns.update(record.keys())
    columns = sorted(list(all_columns))
    
    # 打印表头
    header = " | ".join(f"{col:>12}" for col in columns)
    print_to_file(header)
    print_to_file("-" * len(header))
    
    # 打印数据行
    for i, record in enumerate(results[:max_display]):
        row = " | ".join(f"{str(record.get(col, ''))[:12]:>12}" for col in columns)
        print_to_file(row)
    
    if len(results) > max_display:
        print_to_file(f"... 还有 {len(results) - max_display} 条记录")


class DatabaseSystemDemo:
    """数据库系统演示器"""
    
    def __init__(self):
        # 初始化各个组件
        self.lexical_analyzer = LexicalAnalyzer()
        self.syntax_analyzer = SyntaxAnalyzer()
        self.semantic_analyzer = SemanticAnalyzer()
        self.logical_plan_generator = LogicalPlanGenerator()
        self.physical_plan_optimizer = PhysicalPlanOptimizer()
        
        # 初始化存储引擎适配器（现在使用 DatabaseServerAdapter）
        # 使用项目根目录下的database目录作为数据库根目录
        data_root = "database"
        self.storage_engine = StorageEngineAdapter(
            data_root=data_root,
            database_name="demo_db"
        )
        
        # 用户认证状态
        self.is_logged_in = False
        self.current_user = None
        
        # 初始化查询执行器，传入存储引擎
        self.query_executor = QueryExecutor(storage_engine=self.storage_engine)
        
        # 为语义分析器设置存储适配器，以便动态检查数据库和表的存在性
        self.semantic_analyzer.set_storage_adapter(self.storage_engine)
        
        self.demo_results = {}
    
    def run_sql_demo(self, sql: str, demo_name: str) -> bool:
        """运行单个SQL演示"""
        print_header(f"演示案例: {demo_name}", 1)
        print_to_file(f"SQL语句: {sql}")
        
        start_time = time.time()
        
        try:
            # 步骤1: 词法分析
            print_step(1, "词法分析 (Lexical Analysis)")
            tokens = self.lexical_analyzer.analyze(sql)
            print_tokens(tokens)
            print_to_file("词法分析完成")
            
            # 步骤2: 语法分析
            print_step(2, "语法分析 (Syntax Analysis)")
            syntax_result = self.syntax_analyzer.analyze(tokens)
            
            if syntax_result:
                print_to_file("语法分析成功 - 语法结构正确")
            else:
                print_to_file("语法分析失败 - 语法结构错误")
                return False
            
            # 步骤3: 语义分析
            print_step(3, "语义分析 (Semantic Analysis)")
            quadruples, symbol_table, semantic_errors = self.semantic_analyzer.analyze(tokens)
            
            if semantic_errors:
                print_to_file("语义分析失败:")
                for error in semantic_errors:
                    print_to_file(f"  - {error}")
                return False
            
            print_quadruples(quadruples)
            print_to_file()
            print_symbol_table(symbol_table)
            print_to_file("语义分析完成")
            
            # 步骤4: 逻辑计划生成
            print_step(4, "逻辑计划生成 (Logical Plan Generation)")
            logical_plan = self.logical_plan_generator.generate_logical_plan(quadruples, symbol_table)
            
            if logical_plan:
                print_to_file("生成的逻辑计划:")
                self._print_logical_plan(logical_plan)
                print_to_file("逻辑计划生成完成")
            else:
                print_to_file("无法生成逻辑计划")
                return False
            
            # 步骤5: 物理计划优化
            print_step(5, "物理计划优化 (Physical Plan Optimization)")
            physical_plan = self.physical_plan_optimizer.optimize_to_physical_plan(logical_plan)
            
            if physical_plan:
                print_to_file("优化后的物理执行计划:")
                print_to_file(physical_plan.explain('text'))
                print_to_file("物理计划优化完成")
            else:
                print_to_file("物理计划优化失败")
                return False
            
            # 步骤6: 查询执行
            print_step(6, "查询执行 (Query Execution)")
            context = ExecutionContext()
            results = []
            
            try:
                # 执行物理计划
                for batch in self.query_executor.execute_plan(physical_plan, context):
                    results.extend(batch)
                print_to_file("查询执行完成")
                
                print_execution_results(results)
                
            except Exception as e:
                print_to_file(f"查询执行失败: {str(e)}")
                return False
            
            # 统计信息
            end_time = time.time()
            execution_time = (end_time - start_time) * 1000
            
            print_step(7, "执行统计")
            print_to_file(f"总执行时间: {execution_time:.2f} ms")
            print_to_file(f"Token数量: {len([t for t in tokens if t.type.name not in ['COMMENT', 'EOF']])}")
            print_to_file(f"四元式数量: {len(quadruples)}")
            print_to_file(f"符号表条目: {len(symbol_table)}")
            print_to_file(f"结果记录数: {len(results)}")
            
            self.demo_results[demo_name] = {
                'success': True,
                'execution_time_ms': execution_time,
                'tokens_count': len(tokens),
                'quadruples_count': len(quadruples),
                'results_count': len(results)
            }
            
            print_to_file(f"演示案例 '{demo_name}' 执行成功!")
            return True
            
        except Exception as e:
            print_to_file(f"演示案例 '{demo_name}' 执行失败: {str(e)}")
            import traceback
            traceback.print_exc()
            
            self.demo_results[demo_name] = {
                'success': False,
                'error': str(e)
            }
            return False
    
    def _print_logical_plan(self, logical_plan):
        """打印逻辑计划"""
        def print_node(node, indent=0):
            prefix = "  " * indent
            print_to_file(f"{prefix}- {node.operator_type.value.upper()}")
            if node.properties:
                for key, value in node.properties.items():
                    print_to_file(f"{prefix}  {key}: {value}")
            for child in node.children:
                print_node(child, indent + 1)
        
        print_node(logical_plan)
    
    def login_user(self, username: str = "root", password: str = "root12345") -> bool:
        """用户登录"""
        print_header("用户认证登录", 1)
        print_to_file(f"尝试登录用户: {username}")
        
        try:
            success = self.storage_engine.login(username, password)
            if success:
                self.is_logged_in = True
                self.current_user = username
                print_to_file(f"✅ 用户 {username} 登录成功")
                print_to_file(f"当前用户: {self.storage_engine.get_current_user()}")
                return True
            else:
                print_to_file(f"❌ 用户 {username} 登录失败")
                return False
        except Exception as e:
            print_to_file(f"❌ 登录过程中发生错误: {e}")
            return False
    
    def run_comprehensive_demo(self):
        """运行综合演示"""
        print_header("数据库系统完整功能演示", 1)
        
        # 首先进行用户登录
        if not self.login_user():
            print_to_file("❌ 用户登录失败，无法继续演示")
            return
        
        # 获取完整的数据库系统测试用例
        demo_cases = get_complete_test_cases()
        
        successful_demos = 0
        total_demos = len(demo_cases)
        
        for i, demo_case in enumerate(demo_cases, 1):
            print_to_file(f"\n{'='*20} 执行演示 {i}/{total_demos} {'='*20}")
            print_to_file(f"演示描述: {demo_case['description']}")
            
            success = self.run_sql_demo(demo_case['sql'], demo_case['name'])
            if success:
                successful_demos += 1
            
            # 添加分隔符
            print_to_file("\n" + "▼"*80)
        
        # 演示总结
        self._print_demo_summary(successful_demos, total_demos)
    
    def cleanup(self):
        """清理资源"""
        try:
            if hasattr(self, 'storage_engine') and self.storage_engine:
                print_to_file("\n正在关闭存储引擎...")
                
                # 用户注销
                if self.is_logged_in:
                    print_to_file("用户注销...")
                    self.storage_engine.logout()
                    self.is_logged_in = False
                    self.current_user = None
                    print_to_file("用户注销完成")
                
                # 断开DatabaseServerAdapter连接
                if hasattr(self.storage_engine, 'db_adapter'):
                    self.storage_engine.db_adapter.disconnect()
                    print_to_file("已断开数据库服务器连接")
                
                # 如果有旧的os_storage，则关闭它
                if (hasattr(self.storage_engine, 'os_storage') and 
                    self.storage_engine.os_storage is not None):
                    print_to_file("刷新所有缓存页到磁盘...")
                    self.storage_engine.os_storage.flush_all_pages()
                    print_to_file("保存表结构和映射...")
                    self.storage_engine.os_storage._save_table_schemas()
                    self.storage_engine.os_storage._save_table_mappings()
                    
                    self.storage_engine.close()
                    print_to_file("存储引擎已关闭")
                else:
                    print_to_file("使用DatabaseServerAdapter，无需关闭旧存储引擎")
        except Exception as e:
            print_to_file(f"✗ 关闭存储引擎时出错: {e}")
            import traceback
            traceback.print_exc()
    
    def _print_demo_summary(self, successful: int, total: int):
        """打印演示总结"""
        print_header("演示总结", 1)
        
        print_to_file(f"总演示数: {total}")
        print_to_file(f"成功演示: {successful}")
        print_to_file(f"失败演示: {total - successful}")
        print_to_file(f"成功率: {successful/total*100:.1f}%")
        
        if successful == total:
            print_to_file("\n SUCCESS: 所有演示案例都执行成功!")
        else:
            print_to_file(f"\n ERROR: 有 {total - successful} 个演示案例失败")
        
        # 详细统计
        print_to_file("\n[详细统计]")
        print_to_file(f"{'演示名称':<20} {'状态':<8} {'执行时间':<12} {'结果数':<8}")
        print_to_file("-" * 55)
        
        for demo_name, result in self.demo_results.items():
            if result['success']:
                status = "SUCCESS"
                exec_time = f"{result['execution_time_ms']:.2f}ms"
                result_count = str(result['results_count'])
            else:
                status = "FAILED"
                exec_time = "-"
                result_count = "-"
            
            print_to_file(f"{demo_name:<20} {status:<8} {exec_time:<12} {result_count:<8}")


def main():
    """主函数"""
    global output_mgr
    
    # 初始化输出管理器，创建输出文件
    timestamp = datetime.datetime.now().strftime("%Y%m%d_%H%M%S")
    output_file = f"demo_results_{timestamp}.txt"
    
    with OutputManager(output_file) as output_mgr:
        print_to_file("启动数据库系统完整功能演示")
        print_to_file("本演示将展示从SQL解析到查询执行的完整处理流程")
        print_to_file(f"演示结果将保存到: {output_file}")
        print_to_file(f"演示开始时间: {datetime.datetime.now().strftime('%Y-%m-%d %H:%M:%S')}")
        
        try:
            demo_system = DatabaseSystemDemo()
            demo_system.run_comprehensive_demo()
            
            print_header("演示完成", 1)
            print_to_file("""
恭喜！数据库系统完整功能演示已完成。

通过本次演示，您了解了：
1. SQL词法分析的Token识别过程
2. 语法分析的结构验证过程  
3. 语义分析的四元式生成过程
4. 逻辑计划的生成过程
5. 物理计划的优化过程
6. 查询执行引擎的执行过程

系统特点：
- 完整的SQL编译流水线
- 直观的中间结果展示
- 详细的执行统计信息
- 规范化的错误处理机制
- 支持DDL和DML语句
- Unicode完美支持
            """)
            
        except Exception as e:
            print_to_file(f"\n ERROR: 演示过程中发生严重错误: {str(e)}")
            import traceback
            traceback.print_exc()
        
        finally:
            # 确保清理资源
            if 'demo_system' in locals():
                demo_system.cleanup()


if __name__ == "__main__":
    main()
